from typing import Dict, List, Optional, Any
from dataclasses import dataclass, field
from datetime import datetime
from collections import deque
import threading
from concurrent.futures import ThreadPoolExecutor
import uuid
import time

@dataclass
class TaskStatus:
    PENDING = 'pending'
    RUNNING = 'running'
    COMPLETED = 'completed'
    FAILED = 'failed'

@dataclass
class Task:
    id: str
    filename: str
    kb_id: int
    status: str = TaskStatus.PENDING
    progress: float = 0.0
    message: str = "等待处理"
    created_at: datetime = field(default_factory=datetime.now)
    started_at: Optional[datetime] = None
    completed_at: Optional[datetime] = None
    error: Optional[str] = None
    total_records: int = 0
    processed_records: int = 0

    def __hash__(self):
        return hash(self.id)

    def __eq__(self, other):
        if not isinstance(other, Task):
            return False
        return self.id == other.id

    def update(self, **kwargs):
        """更新任务状态"""
        for key, value in kwargs.items():
            if hasattr(self, key):
                setattr(self, key, value)

class TaskManager:
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                    cls._instance._initialize()
        return cls._instance
    
    def _initialize(self):
        self.tasks = deque(maxlen=20)  # 最近20个任务
        self.active_tasks: Dict[str, Task] = {}  # 正在执行的任务
        self.executor = ThreadPoolExecutor(max_workers=5)  # 最多5个并发任务
        self._lock = threading.Lock()
    
    def create_task(self, filename: str, kb_id: int) -> str:
        """创建新任务"""
        task_id = str(uuid.uuid4())
        task = Task(
            id=task_id,
            filename=filename,
            kb_id=kb_id
        )
        
        with self._lock:
            if len(self.active_tasks) >= 5:
                raise Exception("当前任务队列已满，请稍后再试")
            
            self.tasks.append(task)
            self.active_tasks[task_id] = task
            
        return task_id
    
    def start_task(self, task_id: str):
        """开始执行任务"""
        task = self.get_task(task_id)
        if task:
            task.status = TaskStatus.RUNNING
            task.started_at = datetime.now()
            task.message = "正在处理"
    
    def update_task_progress(self, task_id: str, progress: float, message: str = None):
        """更新任务进度"""
        task = self.get_task(task_id)
        if task:
            task.progress = progress
            if message:
                task.message = message
    
    def complete_task(self, task_id: str, success: bool = True, error: str = None):
        """完成任务"""
        task = self.get_task(task_id)
        if task:
            task.completed_at = datetime.now()
            if success:
                task.status = TaskStatus.COMPLETED
                task.progress = 100.0
                task.message = "处理完成"
            else:
                task.status = TaskStatus.FAILED
                task.error = error
                task.message = f"处理失败: {error}"
            
            with self._lock:
                self.active_tasks.pop(task_id, None)
    
    def get_task(self, task_id: str) -> Optional[Task]:
        """获取任务信息"""
        return self.active_tasks.get(task_id)
    
    def get_all_tasks(self) -> List[Task]:
        """获取所有任务"""
        return list(self.tasks)
    
    def get_active_tasks(self) -> List[Task]:
        """获取活动任务"""
        return list(self.active_tasks.values())

    def update_task(
        self,
        task_id: str,
        status: Optional[str] = None,
        progress: Optional[int] = None,
        message: Optional[str] = None,
        error: Optional[str] = None,
        started_at: Optional[datetime] = None,
        completed_at: Optional[datetime] = None
    ) -> None:
        """更新任务状态"""
        task = self.get_task(task_id)
        if not task:
            return

        if status is not None:
            task.status = status
        if progress is not None:
            task.progress = progress
        if message is not None:
            task.message = message
        if error is not None:
            task.error = error
            task.status = 'failed'
        if started_at is not None:
            task.started_at = started_at
        if completed_at is not None:
            task.completed_at = completed_at

    def check_task_timeout(self):
        """检查任务超时"""
        current_time = datetime.now()
        timeout_seconds = current_app.config['TASK_TIMEOUT']
        
        with self._lock:
            for task_id, task in list(self.active_tasks.items()):
                if task.status == TaskStatus.RUNNING:
                    # 计算任务运行时间
                    elapsed_time = (current_time - task.started_at).total_seconds()
                    if elapsed_time > timeout_seconds:
                        # 标记任务超时
                        task.status = TaskStatus.FAILED
                        task.error = "Task timeout"
                        task.message = "处理超时"
                        self.active_tasks.pop(task_id, None)
                        logger.warning(f"Task {task_id} timed out after {elapsed_time} seconds")

    def start_timeout_checker(self):
        """启动超时检查器"""
        def check_timeouts():
            while True:
                self.check_task_timeout()
                time.sleep(60)  # 每分钟检查一次
        
        threading.Thread(target=check_timeouts, daemon=True).start()

# 全局任务管理器实例
task_manager = TaskManager() 